[iOS] Fix Switch custom colors on iOS 26#35385
Conversation
…net#34527) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details: Horizontalspacing / Verticalspacing is not not applied to the first column in GridItemLayout using CollectionView on Android platform. ### Root Cause: The grid spacing was not being distributed symmetrically across the active layout implementations, so edge items did not fully participate when spacing changed at runtime. ### Description of Change: - On Android, the fix in MauiRecyclerView.cs changes how RecyclerView padding is handled for GridItemsLayout. Android was already using SpacingItemDecoration, which applies half-spacing on all four sides of each item. Previously, negative RecyclerView padding canceled that spacing at the control edges. The branch keeps that negative-padding behavior for non-grid layouts, but disables it for GridItemsLayout, allowing the grid’s half-spacing to remain visible at the outer perimeter. This makes the first row and first column visually respond when spacing changes, but it also changes the grid behavior from spacing only between items to spacing around the outside edges as well. **Tested the behavior in the following platforms:** - [x] Android - [x] Windows - [ ] iOS - [ ] Mac ### Reference: N/A ### Issues Fixed: Fixes dotnet#34257 ### Screenshots | Before | After | |---------|--------| | <Video src="https://github.com/user-attachments/assets/578dda69-1d60-474c-a6d8-23b3f9d29a50" Width="300" Height="600"> | <Video src="https://github.com/user-attachments/assets/7f3826e6-5922-4b6f-a6b9-de581b7db6c3" Width="300" Height="600"> |
…otnet#32491) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Fixes a critical bug where `HybridWebView.InvokeJavaScriptAsync` would timeout when passing JSON strings as parameters. The issue was caused by improper JavaScript string escaping. The fix extracts business logic into a new `HybridWebViewHelper` class and uses `WebViewHelper.EscapeJsString` for proper escaping. **Fixes**: dotnet#32438 --- ## The Problem Issue dotnet#32438 reported that passing JSON strings to `InvokeJavaScriptAsync` caused timeouts on Windows (required base64 encoding as workaround), while Android worked correctly. ### Root Cause The old `EvaluateJavaScriptAsync` implementation used naive string concatenation: ```csharp // OLD - Breaks when script contains quotes script = "try{eval('" + script + "')}catch(e){'null'};"; ``` When the script contained JSON with quotes, this produced invalid JavaScript: ```javascript try{eval('window.HybridWebView.__InvokeJavaScript(1, 'method', ["{\"userId\":\"value\"}"])')}catch(e){'null'}; ↑ BROKEN - conflicting quotes ``` Result: JavaScript execution failed, causing `InvokeJavaScriptAsync` to timeout. --- ## The Solution ### Core Fix New implementation properly escapes JavaScript strings: ```csharp // NEW - Uses proper escaping var escapedScript = WebViewHelper.EscapeJsString(script); var wrappedScript = $$""" (function() { try { let result = eval('{{escapedScript}}'); // ← Properly escaped return JSON.stringify({ IsError: false, Result: JSON.stringify(result) }); } catch (error) { // ... error handling } })() """; ``` ### Refactoring Extracted ~360 lines from `HybridWebViewHandler` into new `HybridWebViewHelper` class: - `ProcessEvaluateJavaScriptAsync` - Script wrapping with proper escaping - `ProcessInvokeJavaScriptAsync` - JavaScript call building - `ProcessInvokeDotNetAsync` - .NET method invocation from JS - `ProcessRawMessage` - Message routing Handler reduced from ~600 to 244 lines. --- ## Changes **New Files:** - ✨ `HybridWebViewHelper.cs` (470 lines) - Centralized business logic **Modified Files:** - 🔧 `HybridWebViewHandler.cs` - Delegates to helper - 🔧 `HybridWebViewHandler.Standard.cs` - Updated message processing - 🔧 `HybridWebViewHandler.Tizen.cs` - Updated message processing **Tests:** - 🔧 `HybridWebViewTestsBase.cs` - Added 15-second timeout - ✨ Added 5 new tests for JSON parameter scenarios - ✨ Added 3 enhanced quote-handling tests - 🔧 Renamed 20+ tests for clarity - 📝 Corrected error messages to use `InvokeJavaScriptAsync` **Test HTML:** - Added `EchoJsonParameter`, `ParseAndStringifyJson`, `ConcatenateJsonStrings`, `DecodeBase64AndEcho`, `CountJsonArrayItems` --- ## Testing **Platforms**: iOS, Android, Windows, MacCatalyst **Scenarios**: - JSON with quotes and special characters - Complex nested JSON - Multiple JSON parameters - Large arrays (100 items) - Base64 workaround (backward compatibility) --- ## Breaking Changes **None** - Fully backward compatible: - ✅ Existing code works unchanged - ✅ Base64 workaround still works - ✅ No public API changes ### Migration Note If using base64 workaround, you can now simplify: ```csharp // OLD workaround (still works): var json = JsonSerializer.Serialize(obj); var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(json)); await hybridWebView.InvokeJavaScriptAsync<string>("fn", ..., [base64], ...); // NEW (now works directly): var json = JsonSerializer.Serialize(obj); await hybridWebView.InvokeJavaScriptAsync<string>("fn", ..., [json], ...); ``` --- ## Checklist - [x] Code follows .NET MAUI conventions - [x] 8 new/enhanced tests added - [x] 20+ tests renamed for clarity - [x] No breaking changes - [x] Backward compatible - [x] Error messages corrected - [x] Formatted with `dotnet format` - [x] XML documentation complete - [x] Tested on multiple platforms --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
… on collection update (dotnet#31275) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause **Windows** Position not updating on item add: CarouselView stayed at the old position after an item was added, leaving current/previous positions unsynced. Cascading events: With `ItemsUpdatingScrollMode.KeepItemsInView`, programmatic smooth scrolls triggered multiple ViewChanged calls, causing `PositionChanged` to fire repeatedly with intermediate values. **Android** Programmatic smooth scrolls produced the same cascading `PositionChanged` events as on Windows. ### Description of Change **Windows** Position Update: On item add, `ItemsView.Position` is explicitly set based on `ItemsUpdatingScrollMode`, keeping current and previous positions in sync. Prevent Cascading Events: Added `_isInternalPositionUpdate`. For collection changes, animations are disabled (animate = false) so scrolling jumps directly, firing `PositionChanged` only once. **Android** Reused the `_isInternalPositionUpdate` logic. Disabled animations during collection changes, ensuring a single clean position update without duplicate events. ### Issues Fixed Fixes dotnet#29529 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <img width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/d66f0352-a91f-4b85-bb9f-e0e54e55aa5f" /> | <img width="350" alt="withfix" src="https://github.com/user-attachments/assets/d120f268-6954-498d-aab0-42bc3745e296" /> | ---------
…3953) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details On iOS/MacCatalyst 26+, when the app theme changes (light ↔ dark), the Switch's ThumbColor resets to white instead of keeping the custom color. ### Root Cause On iOS/MacCatalyst 26+, UIKit resets the UISwitch's ThumbTintColor to its default value during theme transitions. ### Description of Change Register for trait collection changes to detect theme switches, then re-apply the custom ThumbColor after UIKit completes its styling. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#33783 Fixes dotnet#33767 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/aa595096-4f75-4d7e-b31e-f1f0acc24208" >| <video src="https://github.com/user-attachments/assets/386f9e6e-6df7-40c5-a3e7-59a0bde31df6">|
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details WebView does not scroll when placed inside a ScrollView. The parent ScrollView intercepts vertical touch gestures, preventing the WebView from scrolling its internal content. ### Root Cause The parent ScrollView was intercepting all touch events without checking if the child WebView needed to scroll. This prevented the WebView from receiving touch events and handling its own scrolling. ### Description of Change Added touch event handling to prevent parent interception when WebView scrolls. When touch begins or continues, WebView requests exclusive control from parent. When touch ends or cancels, control returns to parent. This enables WebView scrolling while preserving normal parent-child interaction. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#32971 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/12b3ca6e-582d-4a50-9ea1-f49027f2d907" >| <video src="https://github.com/user-attachments/assets/2fbfd03c-4432-49e9-8b2d-6e7643f57487">|
… to null (dotnet#34741) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details On iOS and macCatalyst, setting BackgroundColor = null on an Entry or Editor at runtime does not restore the native default appearance. Once a custom color is applied, it persists even after the property is cleared. ### Root Cause The shared iOS background update logic only resets BackgroundColor = null for LayoutView subclasses — all other UIView types silently return. MauiTextField (Entry) and MauiTextView (Editor) are not LayoutView subclasses, so the reset is skipped. ### Description of Change Platform-specific MapBackground methods were added to EntryHandler.iOS.cs and EditorHandler.iOS.cs. When Background.IsNullOrEmpty(), they now explicitly set platformView.BackgroundColor = null to restore native appearance. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#34611 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/5ca30c6d-c069-4c04-989b-4dae36584cb4" >| <video src="https://github.com/user-attachments/assets/ee9e2a2e-c210-47cc-9f85-2526780d398b">| --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…t placed child to the Border control in iOS/ Mac platform (dotnet#33330) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details: Stacklayout is not rendered when clip is applied and StackLayout placed child to the Border control in iOS/ Mac platform. ### Root Cause: When the clip is applied to the StackLayout, its ContainerView (WrapperView) is being inserted at index 0 to its parent control Border, which places it below Border's background layer in the z-order. As a result, the stacklayout is not visible in the view in iOS and Mac platform. ### Description of Change: The wrapper view is brought to the front of its parent’s subview stack so it renders above the Border background in the Z order. **Tested the behavior in the following platforms.** - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Reference: N/A ### Issues Fixed: Fixes dotnet#33241 ### Screenshots | Before | After | |---------|--------| | <img width="369" height="606" alt="image" src="https://github.com/user-attachments/assets/0be8bc27-5de4-41ad-a41f-92581513ac55" /> | <img width="369" height="606" alt="image" src="https://github.com/user-attachments/assets/6a3590f6-2763-473a-aa91-ee1113e48ec3" /> |
…cription is set (dotnet#33979) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause WinUI `TextBlock` (used by `Label`) automatically exposes its `Text` to UI Automation. `ContentPanel` uses the default `FrameworkElementAutomationPeer`, which exposes both the parent’s `AutomationProperties.Name` and all child elements. Unlike Android (`NoHideDescendants`) or iOS (`AccessibilityElementsHidden`), Windows has no single property to hide descendants while keeping the parent accessible. As a result, both Tab navigation and Browse mode announced duplicate content. ### Description of Change Implemented a custom `ContentPanelAutomationPeer` that overrides three core UI Automation methods (GetAutomationControlTypeCore , `GetLocalizedControlTypeCore`, `GetChildrenCore`) to conditionally modify behavior when Description is present. When a Description exists, the control is exposed as `AutomationControlType.Text` (enables browse mode navigation; alternatives like Custom announce "custom" suffix, Group causes browse mode to skip the element), the "text" announcement suffix is suppressed via empty `GetLocalizedControlTypeCore()` return, and child elements are hidden by returning null from `GetChildrenCore()` to prevent duplication. When no Description is present, default behavior is preserved with `AutomationControlType.Custom` and children remain accessible. The `HasDescription` helper property centralizes the non-empty Description check across all three override methods, ensuring consistent conditional logic following the MAUI `AutomationPeer patterns. ### Issues Fixed Fixes dotnet#33373 ### Platforms Tested - [ ] iOS - [x] Android - [x] Windows - [x] Mac ### Screenshots | Before Fix | After Fix | |------------|-----------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/c5f8f114-fbeb-42d1-8601-e75dad57a1a7" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/d2405df5-64f3-4cd9-8b38-40911ce4fbd6" /> | ---------
…#33459) <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change <img width="870" height="73" alt="image" src="https://github.com/user-attachments/assets/e27cb50d-db93-431b-831c-24f7faedf9b1" /> Invalidation propagation can be quite consuming especially when switching binding context and multiple properties change (i.e. having multiple labels inside a layout, all of them changing the text). Ti PR avoids useless propagations (same behavior `requestLayout` intrinsically has on Android). # Conflicts: # src/Core/src/Platform/iOS/MauiView.cs
…g lifecycle transition (dotnet#34901) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Fixes dotnet#34900 Replaces an opaque `NullReferenceException` with an informative `InvalidOperationException` in `ContainerView` when the Android `Context` is no longer available. ### Root Cause `IMauiContext.Context` (the Android `Context`) is stored via a `WeakReference` to the Activity. During lifecycle transitions (e.g., Activity being GC'd), this reference can become null. When `NavigationRootManager.Connect()` calls `view.ToContainerView(mauiContext)`, it creates a `ContainerView` whose base `LinearLayout` constructor receives a null `Context`, causing an NRE deep in the JNI interop layer. ### Fix Added a null-coalescing throw expression in the `ContainerView` constructor: ```csharp public ContainerView(IMauiContext context) : base(context.Context ?? throw new InvalidOperationException( "Unable to create a ContainerView: the Android Context is no longer available. " + "This can occur when the Activity has been collected during a lifecycle transition.")) ``` This provides a clear, actionable error message instead of the cryptic NRE that pointed at `NavigationRootManager.Connect` line 60. ### Stack trace from the original crash ``` [AndroidRuntime] at Microsoft.Maui.Platform.NavigationRootManager.Connect [AndroidRuntime] at Microsoft.Maui.Handlers.WindowHandler.CreateRootViewFromContent [AndroidRuntime] at Microsoft.Maui.Handlers.WindowHandler.MapContent ``` ---------
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: CarouselView does not utilize the ItemSpacing property during layout styling ### Description of Change Added an item container style based on the horizontal or vertical orientation of the CarouselView, and applied a corresponding style to the ListViewBase <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#29772 ### Tested the behaviour in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac ### Screenshot | Before Issue Fix | After Issue Fix | |----------|----------| | <img src="https://github.com/user-attachments/assets/4af88696-c5a6-4683-bceb-1933781368f3"> | <img src="https://github.com/user-attachments/assets/f55c2b45-22c3-4ab2-aae5-c668adaf33e4"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Detail RadioButtonGroup is not functioning correctly when RadioButton controls are placed inside a ContentView in .NET 10. ### Root Cause PR [dotnet#32640](dotnet#32604) (fixing dotnet#32466) removed the coerceValue and Value = this initialiser from RadioButton, so RadioButton.Value now defaults to null. This introduced two distinct bugs in the ContentView+ControlTemplate scenario: - AddRadioButton guard object.Equals(radioButton.Value, this.SelectedValue) evaluates to object.Equals(null, null) == true, causing every button added via a ControlTemplate to be auto-checked immediately. - When the layout is not yet attached to a Page (common during ControlTemplate inflation), GetVisualRoot() returns null. The original fallback radioButton.Parent resolves to the button's immediate parent (Border), which only contains that single button — so other RadioButtons in the same group are never found and never unchecked. ### Description of Change - Updated the equality check in AddRadioButton to ensure comparison only happens when SelectedValue is not null. This avoids unintended selection during initialization. - Improved the root resolution logic in UncheckOtherRadioButtonsInScope. If no visual root is found, fallback to the RadioButtonGroupController’s layout (group container). ### Issue Fixed Fixes dotnet#34759 ### Screenshots | Before | After | |---------|--------| | <video src="https://github.com/user-attachments/assets/39e1e45d-dd04-42b7-bb85-aea83124b0cb"> | <video src="https://github.com/user-attachments/assets/252587b2-10ae-4eb9-968e-de114756aa0c"> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change I tried to improve the access time on BindableProperty given they're being accessed a lot during the application usage. As we can see using Array + SIMD is actually performing better when the number of BindableProperty set on a BindableObject is less than ~10, though it becomes worse after that. Array + SIMD also (obviously) allocates less memory. Considering that SIMD may perform differently on different platforms I felt it would be better to simply improve the current Dictionary based implementation by leveraging: - integer keys - CollectionMarshal on GetOrAdd ### Benchmarks | Strategy | PropertiesToSet | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | |----------------------- |---------------- |------------:|---------:|---------:|-------:|-------:|----------:| | Dictionary<BindableProperty> | 1 | 65.22 ns | 0.246 ns | 0.218 ns | 0.0889 | 0.0001 | 744 B | | Array + SIMD | 1 | **52.93 ns** | 0.750 ns | 0.665 ns | 0.0678 | - | 568 B | | Dictionary<int,> | 1 | 59.29 ns | 0.563 ns | 0.440 ns | 0.0889 | 0.0001 | 744 B | | | | Dictionary<BindableProperty> | 3 | 150.70 ns | 0.344 ns | 0.322 ns | 0.1500 | 0.0005 | 1256 B | | Array + SIMD | 3 | **122.09 ns** | 0.163 ns | 0.127 ns | 0.1290 | 0.0002 | 1080 B | | Dictionary<int,> | 3 | 133.50 ns | 0.231 ns | 0.180 ns | 0.1500 | 0.0005 | 1256 B | | | | Dictionary<BindableProperty> | 8 | 426.76 ns | 0.686 ns | 0.641 ns | 0.3662 | 0.0033 | 3064 B | | Array + SIMD | 8 | **318.26 ns** | 0.438 ns | 0.409 ns | 0.3028 | 0.0024 | 2536 B | | Dictionary<int,> | 8 | 338.98 ns | 2.381 ns | 1.988 ns | 0.3662 | 0.0038 | 3064 B | | | | Dictionary<BindableProperty> | 15 | 773.49 ns | 2.593 ns | 2.298 ns | 0.5798 | 0.0095 | 4856 B | | Array + SIMD | 15 | 665.18 ns | 0.846 ns | 0.791 ns | 0.5531 | 0.0076 | 4632 B | | Dictionary<int,> | 15 | **581.04 ns** | 0.431 ns | 0.360 ns | 0.5798 | 0.0095 | 4856 B | | | | Dictionary<BindableProperty> | 30 | 1,542.20 ns | 3.342 ns | 3.126 ns | 1.1692 | 0.0381 | 9784 B | | Array + SIMD | 30 | 1,419.83 ns | 1.301 ns | 1.154 ns | 1.0796 | 0.0324 | 9032 B | | Dictionary<int,> | 30 | **1,165.86 ns** | 1.599 ns | 1.496 ns | 1.1692 | 0.0381 | 9784 B | | | | Dictionary<BindableProperty> | 50 | 2,648.69 ns | 3.759 ns | 2.935 ns | 2.0828 | 0.1183 | 17448 B | | Array + SIMD | 50 | 2,587.54 ns | 3.111 ns | 2.429 ns | 1.8196 | 0.0916 | 15224 B | | Dictionary<int,> | 50 | **1,997.17 ns** | 2.174 ns | 2.033 ns | 2.0828 | 0.1183 | 17448 B |
…otnet#33891) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause When a password `Entry` field is empty and text is programmatically set, the obfuscation logic calculates a negative insert position `(0 - 4 = -4)`. String. `Insert()` doesn't accept negative indices, causing an `ArgumentOutOfRangeException` crash in windows. ### Description of Change Added `Math.Max(0, ...)` to clamp the insert position to a minimum of 0, preventing negative **values.** ### Issues Fixed Fixes dotnet#33334 ### Platforms Tested - [x] iOS - [x] Android - [x] Windows - [x] Mac ### Screenshots | Before Fix | After Fix | |------------|-----------| | <img width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/43993544-7700-4bff-a04c-d34b999ac962" /> | <img width="350" alt="withfix" src="https://github.com/user-attachments/assets/e7f12e20-1cd8-45e7-b07d-bfe7ebac6248" /> |
…eaving custom state (dotnet#33346) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: The issue occurs because platform handlers on iOS and Android do not restore button properties to their default values when VisualState setters are removed. In .NET MAUI, when a control transitions from a custom VisualState back to the normal state, property values are set to null to indicate that defaults should be restored. However, the platform handlers interpreted these null values as instructions to take no action, causing previously applied custom values to remain. ### Fix Description: The fix involves updating button-specific extension methods to ensure properties are correctly restored to their platform default values when property values are null. For iOS, the UpdateBackground extension method now explicitly handles UIButton instances. When the background is null or empty, RemoveBackgroundLayer() is called first to prevent stacking gradient layers, and the background is reset to UIColor.Clear. This restores proper transparency and aligns with the default iOS button appearance. When a valid background is provided, the update continues through the existing view background logic. The UpdateTextColor method was also improved to restore the system default text color correctly when TextColor is null. If the button is attached to a UIWindow, the handler clears explicit overrides using SetTitleColor(null, …) for the Normal, Highlighted, and Disabled states, allowing iOS to fall back to its natural appearance-proxy behavior. It then restores TintColor using window.TintColor rather than a hardcoded system color. This ensures the app’s global tint is respected and prevents clearing appearance settings during the initial render phase. For Android, a MaterialButton-specific UpdateTextColor overload was introduced in MauiMaterialButton. The default Material theme ColorStateList is cached as DefaultTextColors during construction, before any MAUI property mapping occurs. When TextColor becomes null, the cached state list is restored directly, preserving all theme-defined states (normal, disabled, etc.). This approach avoids creating temporary controls and guarantees consistent restoration of the original Material theme colors. ### Issues Fixed Fixes dotnet#19690 ### Tested the behaviour in the following platforms - [x] Mac - [x] Windows - [x] iOS - [x] Android ### Output Screenshot | Platform | Before Fix | After Fix | |----------|----------|----------| | Android | <video src="https://github.com/user-attachments/assets/d96c404f-99b0-4dd2-bfdf-01adf629466e"> | <video src="https://github.com/user-attachments/assets/e85313ef-3155-42d3-a1bc-c1b6ef8587b0"> | |iOS | <video src="https://github.com/user-attachments/assets/416724b2-f8fe-4146-be56-12c3f6808693"> | <video src="https://github.com/user-attachments/assets/962ce83a-de7f-4ca0-8339-c8ce88e99288"> |
…tating the device with dialog open (dotnet#31910) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details - On Android, when opening a TimePicker and then rotating the device, the picker dialog doesn’t seem to redraw itself to match the new screen dimensions. ### Root Cause of the issue - TimePicker lacks orientation change detection entirely. When the device rotates while the dialog is open, TimePicker has no mechanism to dismiss and re-show the dialog with updated layout, unlike DatePicker which detects orientation changes and refreshes the dialog display. ### Description of Change - Added ConnectHandler and related event subscriptions (ViewAttachedToWindow/ViewDetachedFromWindow) to manage display info changes and cleanup when the view is attached or detached. This helps ensure the time picker dialog responds to device orientation changes and releases resources properly. - Implemented OnMainDisplayInfoChanged to dismiss and recreate the time picker dialog with the current time when the device orientation changes, preserving user selection progress. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#31658 ### Reference - [DatePickerHandler](https://github.com/dotnet/maui/blob/main/src/Core/src/Handlers/DatePicker/DatePickerHandler.Android.cs) ### Tested the behaviour in the following platforms - [ ] - Windows - [x] - Android - [ ] - Mac - [x] - iOS ### Output | Before | After | |----------|----------| | <video src="https://github.com/user-attachments/assets/55091d04-0aa3-4794-aab8-fb5dfc71624e"> | <video src="https://github.com/user-attachments/assets/56c01750-00a1-4c63-8788-ca6c35d7dbd5"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…#34687) ## Description Fixes dotnet#19866 On iOS, tapping the status bar should scroll the topmost `UIScrollView` to the top. This was not working for `CollectionView`, particularly when hosted inside a `Shell`. ## Root Cause iOS disables its scroll-to-top behavior when **multiple** `UIScrollView` instances in the view hierarchy have `scrollsToTop = true`. The Shell flyout's internal `AccessibilityNeutralTableView` (a `UITableView` subclass) defaults `scrollsToTop` to `true`, conflicting with the `CollectionView`'s `UICollectionView`. ## Fix Two changes: 1. **`ItemsViewController2.ViewDidLoad()`** — Explicitly set `CollectionView.ScrollsToTop = true` to opt in to scroll-to-top behavior 2. **`ShellTableViewController.AccessibilityNeutralTableView`** — Set `ScrollsToTop = false` on Shell's flyout table view to prevent the multi-scroll-view conflict This follows the existing codebase pattern where `ScrollsToTop` is explicitly managed (e.g., `ShellSectionRootHeader` and `ContextActionCell` both set it to `false`). ## Validation Verified with a Sandbox app using a grouped `CollectionView` inside a `Shell` with `TabBar`: - **Without fix**: Diagnostic dump shows two scroll views with `scrollsToTop=True` → status bar tap does nothing - **With fix**: Only `MauiCollectionView` has `scrollsToTop=True` → status bar tap scrolls to top correctly --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ht space above the tab bar even if the page title is empty (dotnet#30382) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root cause The root cause of this issue is that the Windows Shell implementation always reserves space for the header area when Shell.FlyoutBehavior="Flyout" is set, even when pages have no title or header content. The NavigationView control allocates a fixed height above the tab bar for the header region without checking if the current page actually needs this space. This results in an unwanted gap between the flyout toggle area and the tab bar when navigating to pages with empty titles, creating visual inconsistency compared to FlyoutBehavior="Disabled" mode where no header space is reserved for empty content. ### Description of Issue Fix The fix involves adding header visibility logic to the Windows Shell implementation to remove unwanted space above the tab bar in flyout mode. The implementation introduces three key methods in RootNavigationView.cs: UpdateHeaderVisibility() to evaluate header visibility requirements, IsHeaderContentEmpty() to determine if the toolbar contains no title or title view when in flyout mode, and CollapseEmptyHeader() to properly hide empty headers. The toolbar property setter now calls UpdateHeaderVisibility() when the toolbar changes, and ShellView.cs triggers header visibility updates during tab navigation. This ensures empty headers don't occupy unnecessary space in flyout mode while maintaining normal behavior when headers contain content, resolving the spacing issue above the tab bar when switching between pages in Shell applications on Windows. Tested the behavior in the following platforms. - [x] Windows - [x] Mac - [x] iOS - [x] Android ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#30254 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Resaved Test snapshots Resaved the below test snapshot because the ContentPage did not have a title. So, resaved the test snapshot based on the fix. 1. ShellFlowDirectionUpdate 2. VerifyFlyoutBackgroundColor 3. VerifyHamburgerIcon 4. Issue23834FlyoutMisbehavior ### Output | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="270" height="600" src="https://github.com/user-attachments/assets/ca496f96-2500-429f-8720-a8adb7925fce"> | <video width="270" height="600" src="https://github.com/user-attachments/assets/1f0dedd2-4808-46bf-98cf-843ca70294ef"> |
…forms (dotnet#30369) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Detail The FlowDirection property is not respected by the TimePicker control. Setting FlowDirection="RightToLeft" has no visual effect on the control across any platform. ### Root Cause iOS: The MapFlowDirection method incorrectly used the concrete TimePickerHandler type instead of the ITimePickerHandler interface. This bypassed platform-specific logic and defaulted to ViewHandler.MapFlowDirection, which lacked the necessary text alignment handling. Android: The FlowDirection property was not correctly mapped to the native implementation, resulting in incorrect or missing text alignment updates. ### Description of Change iOS: Updated the MapFlowDirection method to use the correct handler interface. Implemented alignment logic in TimePickerExtensions.cs using EffectiveFlowDirection to properly align text for both RTL and LTR layouts. Android: Implemented a platform-specific MapFlowDirection method in TimePickerHandler.Android.cs: For 12-hour format, UpdateTextAlignment is applied to align localized "AM/PM" text based on FlowDirection. For 24-hour format, alignment is handled via UpdateFlowDirection, which sets LayoutDirection and TextDirection to align purely numeric content Validated the behaviour in the following platforms - [x] Android - [ ] Windows dotnet#30322 - [x] iOS - [ ] Mac dotnet#30322 ### Issues Fixed: Fixes dotnet#30192 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/37c4a442-1011-4c23-bc2e-8743bc11adc7"> | <img src="https://github.com/user-attachments/assets/91b69287-b8eb-4d40-b8a1-0734ef1f89db"> |
…dotnet#26217) ### Root cause The issue arises because the OnNavigationViewSizeChanged method fails to properly reset the layout measurements before arranging the NavigationView. As a result, the NavigationView does not correctly update its layout in response to size changes, causing misalignment or rendering issues in the ScrollView. ### Description of Issue Fix The fix involves updating the OnNavigationViewSizeChanged() method to include a call to InvalidateMeasure() before arranging the NavigationView. This ensures that the layout is accurately recalculated, allowing the ScrollView and other elements within the TabbedPage to be properly measured and arranged during the subsequent layout cycle. This effectively resolves alignment and rendering issues. Additionally, the Arrange() call is retained within the SizeChanged handler to prevent test failures, specifically avoiding timeout issues observed in the ChangingToNewMauiContextDoesntCrash test. This combination ensures stable layout behavior while resolving the clipping and scrolling issues that occur after window resizing. ### Why Tests were not added: **Regarding the test case:** The issue only occurs when resizing the window, so it is not possible to add a test case for the window resizing behavior. Tested the behavior in the following platforms. - [x] Windows - [x] Mac - [x] iOS - [x] Android ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#26103 Fixes dotnet#11402 Fixes dotnet#20028 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Resaved Test snapshots Resaved the below-mentioned test snapshot because elements in the TabbedPage were not properly aligned before the fix. The layout changes in OnNavigationViewSizeChanged (adding Arrange() after InvalidateMeasure()) now ensure proper element alignment within the TabbedPage. 1. DefaultSelectedTabTextColorShouldApplyProperly 2. FontImageSourceColorShouldApplyOnTabIcon 3. VerifyTabbedPageMenuItemTextColor 4. DynamicFontImageSourceColorShouldApplyOnTabIcon 5. Issue1323Test 6. TabBarIconsShouldAutoscaleTabbedPage ### Output | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="270" height="600" src="https://github.com/user-attachments/assets/67d34cc9-323c-4a8d-afc6-dbcceb558ee5"> | <video width="270" height="600" src="https://github.com/user-attachments/assets/0ddb5ce5-300a-4088-98f4-f9a3981d6951"> | ---------
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: The UpdateCharacterSpacing method didn't apply spacing to the individual text blocks in TimePicker ### Description of Change Enhanced the UpdateCharacterSpacing method to apply CharacterSpacing to individual text blocks (HourTextBlock, MinuteTextBlock, and PeriodTextBlock) within the TimePicker. This ensures the property works correctly even when the control is loaded asynchronously. <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#30199 ### Tested the behaviour in the following platforms - [x] Windows - [x] Android - [x] iOS - [ ] Mac ### Screenshot | Before Issue Fix | After Issue Fix | |----------|----------| | <img width="1217" height="915" alt="beforeFix30199" src="https://github.com/user-attachments/assets/0b955bf7-5e75-48d3-8455-3fe0cf2c0c5b"> | <img width="1261" height="946" alt="Screenshot 2025-07-10 155258" src="https://github.com/user-attachments/assets/5d2d8a34-fb01-4c58-9fef-be3ad10b7cb0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ---------
…tnet#34383) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…4936) ## Summary - For `Default` and `Fixed` `FlyoutHeaderBehavior`, the flyout scroll view is now positioned below the header instead of overlapping it with a content inset. This prevents items from rendering behind semi-transparent headers when scrolling. - `Scroll` and `CollapseOnScroll` behaviors are unchanged — they still overlap the header so it can scroll away or shrink. - Adds regression test `FlyoutScrollViewDoesNotOverlapHeaderForDefaultAndFixed` and updates `FlyoutHeaderContentAndFooterAllMeasureCorrectly` to match the new layout for Default/Fixed. Fixes dotnet#34925 ## Changes **`ShellFlyoutLayoutManager.cs`** (iOS): - `SetHeaderContentInset()`: For Default/Fixed, sets `ContentInset.Top = 0` since the scroll view frame already starts below the header. - `LayoutContent()`: For Default/Fixed, adds the full header height to the content Y offset instead of just the margin. **`ShellFlyoutTests.cs`**: - New test: `FlyoutScrollViewDoesNotOverlapHeaderForDefaultAndFixed` — verifies the scroll view frame starts at or below the header bottom for Default and Fixed behaviors. - Updated test: `FlyoutHeaderContentAndFooterAllMeasureCorrectly` — adjusts iOS ScrollView expectations so that only Scroll/CollapseOnScroll use content inset; Default/Fixed use frame positioning. ## Test plan - [x] New regression test `FlyoutScrollViewDoesNotOverlapHeaderForDefaultAndFixed` fails without fix, passes with fix - [x] Existing `FlyoutHeaderContentAndFooterAllMeasureCorrectly` test passes with updated expectations - [ ] Manual verification: open flyout with semi-transparent header and 15+ items, scroll down — items should not be visible behind header 🤖 Generated with [Claude Code](https://claude.com/claude-code) ---------
…t#28071) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details When a Margin value is set for the Path, it renders correctly. However, when the Path is placed inside a StackLayout, it does not render. ### Root Cause While measuring the Path, the size calculation does not account for the Margin value, which leads to incorrect path rendering. ### Description of Change To include the Margin value in size calculations and ensure proper Path rendering. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#13801 ### Output ScreenShot | Before | After | |---------|--------| | <img width="501" alt="image (2)" src="https://github.com/user-attachments/assets/7afdacbd-089b-47c2-bad9-216a19618bca" /> | <img width="494" alt="image (3)" src="https://github.com/user-attachments/assets/c64f2eeb-b9c0-4340-beb6-f35fd63f28fc" /> |
…hicsView (dotnet#34557) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details The FlowDirection property is not functioning as expected when applied to Drawable controls and GraphicsView. When FlowDirection is set to either RightToLeft or LeftToRight, there is no observable change in layout behavior. ### Root Cause ShapeViewHandler had no FlowDirection mapper, and ShapeDrawable.Draw() never applied canvas mirroring. ### Description of Change **Android**: Updated PlatformGraphicsView to mirror its content horizontally when the layout direction is RTL by applying a translation and scale transformation in the Draw method. **iOS**: Modified PlatformGraphicsView to check EffectiveUserInterfaceLayoutDirection and apply a horizontal flip transformation when in RTL mode. **Windows**: Changed PlatformGraphicsView to concatenate a scale and translation transform for RTL flow direction before drawing content. ### Validated the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed: Fixes dotnet#34402 ### Screenshots | Before | After | |---------|--------| | <video src="https://github.com/user-attachments/assets/62bec2c7-dbe5-4696-9f78-d2d1b4bcdaec"> | <video src="https://github.com/user-attachments/assets/d143819d-b525-455b-adeb-d589171de61e"> |
…t#34954) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details - HEIC images picked via PickPhotosAsync are not displayed — the image appears blank, whereas other image formats (e.g., JPEG, PNG) display correctly. ### Root Cause of the issue - PR [34250](dotnet#34250) moved CompletedHandler invocation into the DismissViewController completion callback. This introduced a GC race condition where PhotoPickerPresentationControllerDelegate.Dispose() fires tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC transcoding. - HEIC is particularly affected because NSItemProvider.LoadDataRepresentationAsync transcoding is significantly slower than JPEG/PNG loading, widening the GC window. ### Description of Change **Race condition prevention:** * In `PhotoPickerDelegate.DidFinishPicking`, the `Handler` property of `PhotoPickerPresentationControllerDelegate` is set to `null` before dismissing the picker to avoid a garbage collection race condition that could interfere with the async completion handler, especially during slow operations like HEIC transcoding. <!-- Enter description of the fix in this section --> ### Issues Fixed Fixes dotnet#34953 ### Tested the behaviour in the following platforms - [ ] - Windows - [ ] - Android - [x] - iOS - [ ] - Mac | Before | After | |----------|----------| | <video src="https://github.com/user-attachments/assets/368192e4-57ea-4732-82df-3e3ca386ab35"> | <video src="https://github.com/user-attachments/assets/0e3a5066-e092-4461-9199-1730475307d8"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…ion on the second programmatic call (dotnet#34982) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details The issue occurs when calling the SwipeView.Open() method programmatically multiple times on iOS and MacCatalyst platforms. The first call to open swipe items (such as RightItems or BottomItems) works as expected, but the second call throws a System.ArgumentException with the message “An item with the same key has already been added.” This behavior is specific to certain swipe directions that rely on negative offsets (such as right and bottom swipe actions), where the swipe interaction briefly appears and then resets unexpectedly. As a result, internal state inconsistencies lead to a crash during subsequent calls. ### Root Cause The issue occur because of an incorrect use of Math.Abs on the _swipeOffset value inside the ProgrammaticallyOpenSwipeItem()method. This operation removes the negative sign required for specific swipe directions (such as left or up), causing the offset to become invalid during layout validation. Due to this invalid offset, the swipe view resets to a closed state while still retaining previously added entries in the _swipeItems dictionary. When Open() is called again, the same keys are added again to the dictionary, resulting in a duplicate key exception. ### Description of Change The fix involves removing the Math.Abs operation on _swipeOffset to preserve the correct directional value required for swipe behavior, ensuring that the swipe state remains consistent after layout validation. Additionally, a defensive improvement is introduced by clearing the _swipeItems dictionary before repopulating it in the UpdateSwipeItems() method. This prevents duplicate key insertion and ensures that the method behaves safely even if invoked multiple times under unexpected conditions. ### Issues Fixed Fixes dotnet#34917 ### Validated the behaviour in the following platforms - [ ] Windows - [ ] Android - [x] iOS - [x] Mac ### Output | Before | After | |----------|----------| | <video src="https://github.com/user-attachments/assets/55a131cb-6ccc-4776-80d7-90655651565d"> | <video src="https://github.com/user-attachments/assets/5efc010e-04ec-4e4d-8729-d43f41d2d6bf"> |
…ng a NonFlyOutPage (dotnet#34839) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details: Title of FlyOutPage is not updating anymore after showing a NonFlyOutPage in Android Platform. ### Root Cause: When Window.Page is swapped from a FlyoutPage to a plain ContentPage, the Window.Page setter clears flyoutPage.Parent = null synchronously before propagating the Window=null event through the element hierarchy. This means by the time NavigationPage.OnWindowChanged(null) fires to clean up the toolbar, the check flyoutPage.Parent is IWindow evaluates to false (Parent is already null). As a result, flyoutPage.Toolbar = null never executes — the stale, now-disconnected NavigationPageToolbar remains attached to FlyoutPage.Toolbar. When FlyoutPage is later restored as Window.Page, FindMyToolbar() traverses the ancestors, finds the stale toolbar on FlyoutPage.Toolbar, and returns early — no new connected toolbar is created. Since the stale toolbar's ToolbarTracker subscriptions were severed by Disconnect(), it never receives CurrentPage change notifications, so the title is permanently frozen. ### Description of Change: Remove the flyoutPage.Parent is IWindow && condition from the guard in NavigationPage.OnWindowChanged(null) in NavigationPage.cs. The remaining check flyoutPage.Toolbar == _toolbar is the correct and sufficient invariant — it ensures we only clear the toolbar that this NavigationPage created. The Parent is IWindow guard was redundant in the normal case (when FlyoutPage is the root page, Parent is IWindow), but fatally incorrect during a Window.Page swap because the ordering guarantee it depended on didn't hold. **Tested the behavior in the following platforms:** - [x] Android - [ ] Windows - [x] iOS - [x] Mac ### Reference: N/A ### Issues Fixed: Fixes dotnet#33615 ### Screenshots | Before | After | |---------|--------| | <Video src="https://github.com/user-attachments/assets/00869428-8cb4-43a8-981b-7ac6b018e184" Width="300" Height="600"> | <Video src="https://github.com/user-attachments/assets/81f94d6d-8c25-4d08-a699-4b3db32e76c8" Width="300" Height="600"> |
…otnet#34970) <!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> This pull request addresses the issue where the `DatePicker` control on MacCatalyst did not correctly raise its `Opened` and `Closed` events. The changes implement a more robust mechanism for detecting when the DatePicker is opened and closed, specifically for MacCatalyst, and add new tests to verify this behavior. ### Description of Change : **MacCatalyst DatePicker Event Handling Improvements:** * Added logic to traverse the internal view hierarchy of the compact `UIDatePicker` to find and wire up `UITextField` subviews, allowing detection of when the DatePicker is opened via the `EditingDidBegin` event. A one-shot observer is registered to detect when the picker popover window closes, ensuring the `Closed` event is raised reliably. (`DatePickerHandler.MacCatalyst.cs`) * Implemented cleanup logic to unwire event handlers and remove observers during disconnect, preventing memory leaks and spurious event firing. (`DatePickerHandler.MacCatalyst.cs`) * Removed previous event handler attachments (`EditingDidBegin`/`EditingDidEnd`) from the proxy, as the new mechanism supersedes them. (`DatePickerHandler.MacCatalyst.cs`) [[1]](diffhunk://#diff-2107542f6f788907263db46eab6a80232ed765aa515806945e8f65681c8421d1L105-L113) [[2]](diffhunk://#diff-2107542f6f788907263db46eab6a80232ed765aa515806945e8f65681c8421d1L125-L136) **Testing Enhancements:** * Added a new test case page (`Issue34848`) and a corresponding UI test to verify that the `Opened` and `Closed` events are raised correctly on MacCatalyst and other platforms, using platform-specific logic to close the DatePicker. (`TestCases.HostApp/Issues/Issue34848.cs`, `TestCases.Shared.Tests/Tests/Issues/Issue34848.cs`) [[1]](diffhunk://#diff-652f2cd8a1e252cf8db29bf33034066d08ec5e3b43ec76a77d477824a08a1f44R1-R46) [[2]](diffhunk://#diff-a57ba10bf75c97b2a6f28c075585a1066df8c7c2c31751e3c799177fca6560b4R1-R42) **General Codebase Improvements:** * Minor code cleanup and improved organization in the DatePicker handler for MacCatalyst, including the addition of necessary using directives. (`DatePickerHandler.MacCatalyst.cs`) <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#34848 ### Tested the behavior in the following platforms - [ ] Windows - [ ] Android - [ ] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/73c4686f-30d0-4a57-bb8d-be6b2d4b7cda"> | <video src="https://github.com/user-attachments/assets/65d6f44e-b145-48de-b41a-77b6abefabc4"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
|
/review -b feature/enhanced-reviewer |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 2 findings
See inline comments for details.
Test Failure Review
❔ Test Failure Review —
|
| Failure | Verdict | Evidence |
|---|---|---|
maui-pr-uitests build 1445326 incomplete UI-test run |
Insufficient data | Build 1445326 is maui-pr-uitests (definition 313) on refs/pull/35385/merge, status inProgress, result null. The rollup check is QUEUED, and child checks for Android CollectionView, iOS CollectionView1, iOS SearchBar/Shape/Slider, macOS CarouselView, and macOS CollectionView are still IN_PROGRESS, so the UI-test result is not final. |
maui-pr-uitests timeline task issues |
Insufficient data | Six timeline records contain only PowerShell exited with code '1'. plus retry warnings: Controls WebView, Controls Page,Performance,Picker,ProgressBar, Controls (vlatest) Border,BoxView,Brush,Button, Controls Lifecycle,ManualReview,Maps, Controls (vlatest) Editor,Effects,Essentials,FlyoutPage,Focus,Fonts,Frame,Gestures,GraphicsView, and Controls ListView. Each record has result: succeeded after retry and no log id/log excerpt in the gathered context, so there is no test name, stack trace, or failure message to attribute or dismiss. |
| 53 raw / 23 unique authenticated AzDO test-result failures | Likely unrelated | The extracted failures are Roslyn/CodeAnalysis, JIT, readytorun/crossgen2, and GC tests such as Microsoft.CodeAnalysis.*OrganizeImports*, JIT/Performance/CodeQuality/Roslyn/CscBench, readytorun/*crossgen2determinism*, and GC/GetTotalPauseDuration on Windows/unknown platforms. They do not reference changed files or tests; this PR changes iOS/macOS Switch handler code, iOS 26 visual snapshots, and SwitchHandlerTests.iOS.cs. Recent main-branch runs of the same UI-test definition also include failures: 1444191, 1431731, 1419912, and 1419503 failed. |
Recommended action
Regather the review context after maui-pr-uitests build 1445326 completes so the final UI shard results and logs are available; do not attribute the Roslyn/CoreCLR/GC test-result failures to this PR unless new evidence ties them to the changed iOS Switch files.
Evidence details
- Context generated:
2026-06-02T14:08:58.7437180Zfor PR [iOS] Fix Switch custom colors on iOS 26 #35385. - PR metadata: head commit
1a4ae2963237d31f2d3eb052039c1ad3f2fa0a22; basemain; labelscommunity ✨,s/agent-reviewed, ands/agent-fix-pr-picked. - PR scope from changed files: inferred platforms
ios,macos; area hintsHandler,DeviceTests; changed files includesrc/Core/src/Handlers/Switch/SwitchHandler.iOS.cs,src/Core/src/Platform/iOS/MauiSwitch.cs,src/Core/src/Platform/iOS/SwitchExtensions.cs,src/Core/tests/DeviceTests/Handlers/Switch/SwitchHandlerTests.iOS.cs, and iOS 26 snapshots for CheckBox, DatePicker, Editor, RadioButton, SearchBar, Slider, Switch, and visual state tests. - Completed checks in the gathered context:
maui-prbuild 1445325 succeeded, andmaui-pr-devicetestsbuild 1445327 succeeded. - Device-test limitation: no Helix aggregate data was included for
maui-pr-devicetests, so hidden XHarness/Helix failures could not be independently verified from this context. maui-pr-uitestsbuild 1445326 metadata: build number10.0.80-ci+pr.35385.azdo.1445326, definitionmaui-pr-uitests(313), statusinProgress, resultnull, source branchrefs/pull/35385/merge, source version25891cebad3019e93c84bef6cbdd9756940f379e, started2026-06-02T13:59:45.695986Z.- Inconclusive UI-test checks at gather time:
maui-pr-uitestsrollupQUEUED;Build AnalysisIN_PROGRESS; Android CollectionView, iOS CollectionView1, iOS SearchBar/Shape/Slider, macOS CarouselView, and macOS CollectionView child checksIN_PROGRESS. - Timeline task issues in build 1445326: six task records had
PowerShell exited with code '1'.andRetryHelper encountered task failure, will retry (attempt #: 1 out of 1) after 1000 ms, but the task records are markedresult: succeededand have no log id attached in the gathered context. - Authenticated AzDO test results for build 1445326 returned 53 raw failures, deduplicated to 23 unique test/platform groups. Representative unrelated groups include Roslyn
OrganizeImportscase-sensitivity assertions, JITssaNum != SsaConfig::RESERVED_SSA_NUMassertions, readytorun/crossgen2 determinism crashes, and GCGetTotalPauseDurationfailures across run IDs including 119522, 121634, 129430, 129438, 129640, 129780, and 129808. - Recent base-branch comparison for
maui-pr-uitests: build 1444191 failed, 1432188 succeeded, 1431731 failed, 1419912 failed, and 1419503 failed onrefs/heads/main. - Data limitation: authenticated AzDO access used an Azure CLI bearer token for local-only data gathering; the gh-aw workflow relies on public build/timeline/log APIs unless
AZDO_TOKENis provided by the runner environment.
# Conflicts: # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_CheckBox_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_DatePicker_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_Editor_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_RadioButton_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_SearchBar_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_Slider_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_Switch_VerifyVisualState.png # src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/LightTheme_VerifyVisualState.png # src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs
|
/review -b feature/enhanced-reviewer |
This comment has been minimized.
This comment has been minimized.
|
/review -b feature/enhanced-reviewer |
This comment has been minimized.
This comment has been minimized.
|
/review -b feature/enhanced-reviewer |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
|
|
||
| try | ||
| { | ||
| this.ApplyTrackColor(virtualView); |
There was a problem hiding this comment.
[major] Handler Mapper and Property Patterns — This lifecycle reapply path writes TrackColor/ThumbColor directly via ApplyTrackColor/ApplyThumbColor, so any app or library customization registered with SwitchHandler.Mapper.AppendToMapping/PrependToMapping for TrackColor or ThumbColor is skipped after MovedToWindow/LayoutSubviews/TraitCollectionDidChange. Concrete scenario: an app appends a mapping that adjusts the native switch color after MAUI maps TrackColor; it works initially, but an iOS 26 trait/window reapply overwrites it with the raw virtual-view colors. Please route reapply through the handler mapper (for example Handler.UpdateValue for the affected properties) or otherwise preserve mapper customizations.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@AdamEssenmacher — new AI review results are available based on this last commit:
b707a1c.
** [MacCatalyst] Fix DatePicker Opened/Closed events not being raised (#34970)** To request a fresh review after new comments or commits, comment/review rerun.
Review Sessions — click to expand
Gate — Test Before & After Fix
Gate Result: ❌ FAILED
Platform: ANDROID · Base: main · Merge base: e904e900
🩺 Fix does not pass the tests — every test still fails after applying the fix. The PR's change does not resolve the failure(s).
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
📱 SwitchHandlerTests (DefaultSwitchReappliesLegacyOffTrackColorBeforeiOSOrMacCatalyst26, CustomColorsUseSlidingStyleOniOSOrMacCatalyst26, CustomColorsRenderOnInitialOffStateOniOSOrMacCatalyst26, DefaultSwitchUsesAutomaticStyleOniOSOrMacCatalyst26, ThumbColorClearsWhenResetOniOSOrMacCatalyst26, CustomColorsClearToAutomaticStyleOniOSOrMacCatalyst26, CustomColorsReapplyAfterMovedToWindowOniOSOrMacCatalyst26, QueuedColorReapplyDoesNotUpdateStaleNativeSwitchAfterReconnectOniOSOrMacCatalyst26, CustomColorsReapplyAfterWillEnterForegroundOniOS26, CustomColorsUpdateAfterAppThemeChangeOniOSOrMacCatalyst26) Category=Switch |
✅ FAIL — 506s | ❌ FAIL — 651s |
🔴 Without fix — 📱 SwitchHandlerTests (DefaultSwitchReappliesLegacyOffTrackColorBeforeiOSOrMacCatalyst26, CustomColorsUseSlidingStyleOniOSOrMacCatalyst26, CustomColorsRenderOnInitialOffStateOniOSOrMacCatalyst26, DefaultSwitchUsesAutomaticStyleOniOSOrMacCatalyst26, ThumbColorClearsWhenResetOniOSOrMacCatalyst26, CustomColorsClearToAutomaticStyleOniOSOrMacCatalyst26, CustomColorsReapplyAfterMovedToWindowOniOSOrMacCatalyst26, QueuedColorReapplyDoesNotUpdateStaleNativeSwitchAfterReconnectOniOSOrMacCatalyst26, CustomColorsReapplyAfterWillEnterForegroundOniOS26, CustomColorsUpdateAfterAppThemeChangeOniOSOrMacCatalyst26): FAIL ✅ · 506s
(truncated to last 15,000 chars)
8Ho/H4/F4PB6Px+PxeNoTudAn8P+c/P13F+wscnhBNJf57q80rOfFMJ8wzotgvCCWn8bCXmi9kfnEsRjRLBkviOWh8T5Kw6eaZ9v5XEZ+3TZ81yiGZRWHF8TSaSzgvAjywpAfAxWDXF777Mr9dwJcCO49sCG4V1IhOGYLIS+OplgML4hzZ64nXTWurwPpA9UHcgz4XeAWkCLoXhABceBGwVXBPAPub4A1wAi4EbCDdQHkBdFoORrXl3xRnsXTKAYFyGaQPaA+BvIBEIO6Cwq/BX290HcCLumA9WVYq2BlAEUHIRAbqFo4VYHDU/D+Kjg0CiN/DyMPQhSCvRR4sS6GvEiWTRReEGfPLDdAThBrQa8HdxsEt8LAari2CB8pw/UhXCmwSkEnUJb0P87VdyguLdyKhUkHJxJ4awp2TsGOEdj9NAw9Bsn7IIfBcLo45oszzvriPIsjCw5niWEt6MPg/gD4FdhwDdysYFsI1ytYDxTIFZKQlqICV/vEgqjaRrl6qACRhfdj2Gnh+TfhuYfgwF8Da+vCmEsUmUs5K7wgFsd8VkFthiCC+DroehDuKMDtCrYo6AOC3H9
06-03 05:57:35.821 8666 8827 I DOTNET : Exception stack traces: at Microsoft.Maui.DeviceTests.AssertionExtensions.<>c__DisplayClass32_0.<AssertContainsColor>b__0()
06-03 05:57:35.821 8666 8827 I DOTNET : at System.Threading.Tasks.Task`1[[Android.Graphics.Bitmap, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]].InnerInvoke()
06-03 05:57:35.821 8666 8827 I DOTNET : at System.Threading.Tasks.Task.<>c.<.cctor>b__288_0(Object obj)
06-03 05:57:35.821 8666 8827 I DOTNET : at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )
06-03 05:57:35.821 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.821 8666 8827 I DOTNET : at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )
06-03 05:57:35.821 8666 8827 I DOTNET : at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& , Thread )
06-03 05:57:35.821 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.821 8666 8827 I DOTNET : at Microsoft.Maui.DeviceTests.AssertionExtensions.AssertContainsColor(View view, Color expectedColor, IMauiContext mauiContext, Nullable`1 tolerance)
06-03 05:57:35.821 8666 8827 I DOTNET : at Microsoft.Maui.DeviceTests.HandlerTestBasement.<>c__DisplayClass18_0.<<ValidateHasColor>b__0>d.MoveNext()
06-03 05:57:35.821 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.821 8666 8827 I DOTNET : at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
06-03 05:57:35.821 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.821 8666 8827 I DOTNET : at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
06-03 05:57:35.821 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.821 8666 8827 I DOTNET : at Microsoft.Maui.DeviceTests.SwitchHandlerTests.ThumbColorUpdatesCorrectly()
06-03 05:57:35.821 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.821 8666 8827 I DOTNET : Execution time: 0.2967801
06-03 05:57:35.821 8666 8827 I DOTNET : Test trait name: Category
06-03 05:57:35.821 8666 8827 I DOTNET : value: Switch
06-03 05:57:35.821 8666 8827 I DOTNET : [FAIL] Thumb Color Updates Correctly
06-03 05:57:35.821 8666 8827 I DOTNET : [FAIL] Thumb Color Updates Correctly Test name: Thumb Color Updates Correctly
06-03 05:57:35.821 8666 8827 I DOTNET : Assembly: [Microsoft.Maui.Core.DeviceTests, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]
06-03 05:57:35.821 8666 8827 I DOTNET : Exception messages: Color Color [A=255, R=255, G=0, B=0] not found. This is what it looked like:<img>iVBORw0KGgoAAAANSUhEUgAAAIQAAACECAYAAABRRIOnAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAA/rSURBVHic7Z17jB3Vfcc/v3Nm7mMf9u567QVjMDYuD2NMk7agKGkxhTTpU6iCVG1FGlo1UdWmUtWHQqMKXKlVioRKojRRWjVUrdSWh1pUgigtLyUNJBQwxtjYYDCY9WO99q69r7t3Zs45/WPu7J293vWuvXvte+n5SKM7unfuvM53fr/f+Z3HgMfj8Xg8Ho/H4/F4PB6Px+PxeDwej8fj8Xg8Ho/H4/F4PB6Px+PxeDwej8fj8Xg8Ho/H4/F4PB6Px+PxeNoTudAn8P+c/P13F+wscnhBNJf57q80rOfFMJ8wzotgvCCWn8bCXmi9kfnEsRjRLBkviOWh8T5Kw6eaZ9v5XEZ+3TZ81yiGZRWHF8TSaSzgvAjywpAfAxWDXF777Mr9dwJcCO49sCG4V1IhOGYLIS+OplgML4hzZ64nXTWurwPpA9UHcgz4XeAWkCLoXhABceBGwVXBPAPub4A1wAi4EbCDdQHkBdFoORrXl3xRnsXTKAYFyGaQPaA+BvIBEIO6Cwq/BX290HcCLumA9WVYq2BlAEUHIRAbqFo4VYHDU/D+Kjg0CiN/DyMPQhSCvRR4sS6GvEiWTRReEGfPLDdAThBrQa8HdxsEt8LAari2CB8pw/UhXCmwSkEnUJb0P87VdyguLdyKhUkHJxJ4awp2TsGOEdj9NAw9Bsn7IIfBcLo45oszzvriPIsjCw5niWEt6MPg/gD4FdhwDdysYFsI1ytYDxTIFZKQlqICV/vEgqjaRrl6qACRhfdj2Gnh+TfhuYfgwF8Da+vCmEsUmUs5K7wgFsd8VkFthiCC+DroehDuKMDtCrYo6AOC3H9
06-03 05:57:35.862 8666 8827 I DOTNET : at System.Threading.Tasks.Task.<>c.<.cctor>b__288_0(Object obj)
06-03 05:57:35.862 8666 8827 I DOTNET : at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )
06-03 05:57:35.862 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.862 8666 8827 I DOTNET : at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )
06-03 05:57:35.862 8666 8827 I DOTNET : at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& , Thread )
06-03 05:57:35.862 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.862 8666 8827 I DOTNET : at Microsoft.Maui.DeviceTests.AssertionExtensions.AssertContainsColor(View view, Color expectedColor, IMauiContext mauiContext, Nullable`1 tolerance)
06-03 05:57:35.862 8666 8827 I DOTNET : at Microsoft.Maui.DeviceTests.HandlerTestBasement.<>c__DisplayClass18_0.<<ValidateHasColor>b__0>d.MoveNext()
06-03 05:57:35.862 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.862 8666 8827 I DOTNET : at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
06-03 05:57:35.862 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.862 8666 8827 I DOTNET : at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
06-03 05:57:35.862 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.862 8666 8827 I DOTNET : at Microsoft.Maui.DeviceTests.SwitchHandlerTests.ThumbColorUpdatesCorrectly()
06-03 05:57:35.862 8666 8827 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:35.862 8666 8827 I DOTNET : Execution time: 0.2967801
06-03 05:57:35.862 8666 8827 I DOTNET : Test trait name: Category
06-03 05:57:35.862 8666 8827 I DOTNET : value: Switch
06-03 05:57:35.862 8666 8827 I DOTNET :
06-03 05:57:35.875 8666 8827 I DOTNET : [PASS] RotationX Initialize Correctly
06-03 05:57:35.880 8666 8827 I DOTNET : [PASS] RotationX Initialize Correctly
06-03 05:57:35.891 8666 8827 I DOTNET : [PASS] Null Thumb Color Doesn't Crash
06-03 05:57:35.905 8666 8827 I DOTNET : [PASS] Setting Semantic Description makes element accessible
06-03 05:57:35.915 8666 8827 I DOTNET : [PASS] Is Toggled Initializes Correctly
06-03 05:57:35.949 8666 8827 I DOTNET : [PASS] FlowDirection is set correctly
06-03 05:57:35.961 8666 8827 I DOTNET : [PASS] FlowDirection is set correctly
06-03 05:57:36.011 8666 8827 I DOTNET : [PASS] Opacity is set correctly
06-03 05:57:36.026 8666 8827 I DOTNET : [PASS] Opacity is set correctly
06-03 05:57:36.026 8666 8827 I DOTNET : [IGNORED] Semantic Hint is set correctly
06-03 05:57:36.030 8666 8827 I DOTNET : [PASS] DisconnectHandlerDoesntCrash
06-03 05:57:36.033 8666 8827 I DOTNET : [PASS] HandlersHaveAllExpectedContructors
06-03 05:57:36.052 8666 8827 I DOTNET : [PASS] Rotation Initialize Correctly
06-03 05:57:36.057 8666 8827 I DOTNET : [PASS] Rotation Initialize Correctly
06-03 05:57:36.072 8666 8827 I DOTNET : [PASS] MinimumHeightInitializes
06-03 05:57:36.074 8666 8827 I DOTNET : [PASS] MinimumHeightInitializes
06-03 05:57:36.102 8666 8827 I DOTNET : [PASS] Visibility is set correctly
06-03 05:57:36.106 8666 8827 I DOTNET : [PASS] Visibility is set correctly
06-03 05:57:36.117 8666 8827 I DOTNET : [PASS] Updating Native Is On property updates Virtual View
06-03 05:57:36.120 8666 8827 I DOTNET : [PASS] Native View Bounds are not empty
06-03 05:57:36.122 8666 8827 I DOTNET : [PASS] Native View Bounds are not empty
06-03 05:57:36.127 8666 8827 I DOTNET : [PASS] ScaleY Initialize Correctly
06-03 05:57:36.129 8666 8827 I DOTNET : [PASS] ScaleY Initialize Correctly
06-03 05:57:36.133 8666 8827 I DOTNET : [PASS] Clip Initializes ContainerView Correctly
06-03 05:57:36.228 8666 8827 I DOTNET : [PASS] Automation Id is set correctly
06-03 05:57:36.233 8666 8827 I DOTNET : [PASS] Null Semantics Doesnt throw exception
06-03 05:57:36.246 8666 8827 I DOTNET : [PASS] Semantic Heading is set correctly
06-03 05:57:36.262 8666 8827 I DOTNET : [PASS] Setting Semantic Hint makes element accessible
06-03 05:57:36.304 8666 8827 I DOTNET : Microsoft.Maui.DeviceTests.SwitchHandlerTests 1.8459761 ms
06-03 05:57:36.320 8666 8747 I DOTNET : Failed tests:
06-03 05:57:36.321 8666 8747 I DOTNET : 1) [FAIL] Thumb Color Updates Correctly Test name: Thumb Color Updates Correctly
06-03 05:57:36.321 8666 8747 I DOTNET : Assembly: [Microsoft.Maui.Core.DeviceTests, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]
06-03 05:57:36.321 8666 8747 I DOTNET : Exception messages: Color Color [A=255, R=255, G=0, B=0] not found. This is what it looked like:<img>iVBORw0KGgoAAAANSUhEUgAAAIQAAACECAYAAABRRIOnAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAA/rSURBVHic7Z17jB3Vfcc/v3Nm7mMf9u567QVjMDYuD2NMk7agKGkxhTTpU6iCVG1FGlo1UdWmUtWHQqMKXKlVioRKojRRWjVUrdSWh1pUgigtLyUNJBQwxtjYYDCY9WO99q69r7t3Zs45/WPu7J293vWuvXvte+n5SKM7unfuvM53fr/f+Z3HgMfj8Xg8Ho/H4/F4PB6Px+PxeDwej8fj8Xg8Ho/H4/F4PB6Px+PxeDwej8fj8Xg8Ho/H4/F4PB6Px+PxeNoTudAn8P+c/P13F+wscnhBNJf57q80rOfFMJ8wzotgvCCWn8bCXmi9kfnEsRjRLBkviOWh8T5Kw6eaZ9v5XEZ+3TZ81yiGZRWHF8TSaSzgvAjywpAfAxWDXF777Mr9dwJcCO49sCG4V1IhOGYLIS+OplgML4hzZ64nXTWurwPpA9UHcgz4XeAWkCLoXhABceBGwVXBPAPub4A1wAi4EbCDdQHkBdFoORrXl3xRnsXTKAYFyGaQPaA+BvIBEIO6Cwq/BX290HcCLumA9WVYq2BlAEUHIRAbqFo4VYHDU/D+Kjg0CiN/DyMPQhSCvRR4sS6GvEiWTRReEGfPLDdAThBrQa8HdxsEt8LAari2CB8pw/UhXCmwSkEnUJb0P87VdyguLdyKhUkHJxJ4awp2TsGOEdj9NAw9Bsn7IIfBcLo45oszzvriPIsjCw5niWEt6MPg/gD4FdhwDdysYFsI1ytYDxTIFZKQlqICV/vEgqjaRrl6qACRhfdj2Gnh+TfhuYfgwF8Da+vCmEsUmUs5K7wgFsd8VkFthiCC+DroehDuKMDtCrYo6AOC3H9
06-03 05:57:36.321 8666 8747 I DOTNET : at System.Threading.Tasks.Task.<>c.<.cctor>b__288_0(Object obj)
06-03 05:57:36.321 8666 8747 I DOTNET : at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )
06-03 05:57:36.321 8666 8747 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:36.321 8666 8747 I DOTNET : at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )
06-03 05:57:36.321 8666 8747 I DOTNET : at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& , Thread )
06-03 05:57:36.321 8666 8747 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:36.321 8666 8747 I DOTNET : at Microsoft.Maui.DeviceTests.AssertionExtensions.AssertContainsColor(View view, Color expectedColor, IMauiContext mauiContext, Nullable`1 tolerance)
06-03 05:57:36.321 8666 8747 I DOTNET : at Microsoft.Maui.DeviceTests.HandlerTestBasement.<>c__DisplayClass18_0.<<ValidateHasColor>b__0>d.MoveNext()
06-03 05:57:36.321 8666 8747 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:36.321 8666 8747 I DOTNET : at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
06-03 05:57:36.321 8666 8747 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:36.321 8666 8747 I DOTNET : at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
06-03 05:57:36.321 8666 8747 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:36.321 8666 8747 I DOTNET : at Microsoft.Maui.DeviceTests.SwitchHandlerTests.ThumbColorUpdatesCorrectly()
06-03 05:57:36.321 8666 8747 I DOTNET : --- End of stack trace from previous location ---
06-03 05:57:36.321 8666 8747 I DOTNET : Execution time: 0.2967801
06-03 05:57:36.321 8666 8747 I DOTNET : Test trait name: Category
06-03 05:57:36.321 8666 8747 I DOTNET : value: Switch
06-03 05:57:36.321 8666 8747 I DOTNET :
06-03 05:57:36.413 8666 8747 I DOTNET : Xml file was written to the provided writer.
06-03 05:57:36.414 8666 8747 I DOTNET : Tests run: 1314 Passed: 66 Inconclusive: 0 Failed: 1 Ignored: 1244
�[41m�[30mfail�[39m�[22m�[49m: Non-success instrumentation exit code: 1, expected: 0
�[40m�[32minfo�[39m�[22m�[49m: <<XHARNESS_RESULT_START>>
{
"version": 1,
"machineName": "runnervmm79r7",
"exitCode": 1,
"exitCodeName": "TESTS_FAILED",
"platform": "android",
"instrumentationExitCode": 1,
"device": "emulator-5554",
"deviceOsVersion": "API 30",
"architecture": "x86_64",
"files": [
{
"name": "testResults.xml",
"type": "test-results"
},
{
"name": "adb-logcat-com.microsoft.maui.core.devicetests-default.log",
"type": "logcat"
}
]
}
<<XHARNESS_RESULT_END>>
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.core.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.core.devicetests'
�[40m�[32minfo�[39m�[22m�[49m: Successfully uninstalled com.microsoft.maui.core.devicetests
XHarness exit code: 1 (TESTS_FAILED)
Tests completed with exit code: 1
🟢 With fix — 📱 SwitchHandlerTests (DefaultSwitchReappliesLegacyOffTrackColorBeforeiOSOrMacCatalyst26, CustomColorsUseSlidingStyleOniOSOrMacCatalyst26, CustomColorsRenderOnInitialOffStateOniOSOrMacCatalyst26, DefaultSwitchUsesAutomaticStyleOniOSOrMacCatalyst26, ThumbColorClearsWhenResetOniOSOrMacCatalyst26, CustomColorsClearToAutomaticStyleOniOSOrMacCatalyst26, CustomColorsReapplyAfterMovedToWindowOniOSOrMacCatalyst26, QueuedColorReapplyDoesNotUpdateStaleNativeSwitchAfterReconnectOniOSOrMacCatalyst26, CustomColorsReapplyAfterWillEnterForegroundOniOS26, CustomColorsUpdateAfterAppThemeChangeOniOSOrMacCatalyst26): FAIL ❌ · 651s
(truncated to last 15,000 chars)
tlinX.Serialization.Core.Jvm.dll.so
[60/128] xunit.abstractions.dll -> xunit.abstractions.dll.so
[61/128] xunit.assert.dll -> xunit.assert.dll.so
[62/128] xunit.core.dll -> xunit.core.dll.so
[63/128] xunit.execution.dotnet.dll -> xunit.execution.dotnet.dll.so
[64/128] xunit.runner.utility.netcoreapp10.dll -> xunit.runner.utility.netcoreapp10.dll.so
[65/128] System.Collections.Concurrent.dll -> System.Collections.Concurrent.dll.so
[66/128] System.Collections.Immutable.dll -> System.Collections.Immutable.dll.so
[67/128] System.Collections.NonGeneric.dll -> System.Collections.NonGeneric.dll.so
[68/128] System.Collections.Specialized.dll -> System.Collections.Specialized.dll.so
[128/128] System.Private.CoreLib.dll -> System.Private.CoreLib.dll.so
[69/128] System.Collections.dll -> System.Collections.dll.so
[70/128] System.ComponentModel.Primitives.dll -> System.ComponentModel.Primitives.dll.so
[71/128] System.ComponentModel.TypeConverter.dll -> System.ComponentModel.TypeConverter.dll.so
[72/128] System.ComponentModel.dll -> System.ComponentModel.dll.so
[73/128] System.Console.dll -> System.Console.dll.so
[74/128] System.Diagnostics.Debug.dll -> System.Diagnostics.Debug.dll.so
[75/128] System.Diagnostics.DiagnosticSource.dll -> System.Diagnostics.DiagnosticSource.dll.so
[76/128] System.Diagnostics.Process.dll -> System.Diagnostics.Process.dll.so
[77/128] System.Diagnostics.Tools.dll -> System.Diagnostics.Tools.dll.so
[78/128] System.Diagnostics.TraceSource.dll -> System.Diagnostics.TraceSource.dll.so
[79/128] System.Diagnostics.Tracing.dll -> System.Diagnostics.Tracing.dll.so
[80/128] System.Drawing.Primitives.dll -> System.Drawing.Primitives.dll.so
[81/128] System.Drawing.dll -> System.Drawing.dll.so
[82/128] System.Formats.Asn1.dll -> System.Formats.Asn1.dll.so
[83/128] System.Globalization.dll -> System.Globalization.dll.so
[84/128] System.IO.Compression.Brotli.dll -> System.IO.Compression.Brotli.dll.so
[85/128] System.IO.Compression.dll -> System.IO.Compression.dll.so
[86/128] System.IO.FileSystem.dll -> System.IO.FileSystem.dll.so
[87/128] System.IO.Pipelines.dll -> System.IO.Pipelines.dll.so
[88/128] System.IO.dll -> System.IO.dll.so
[89/128] System.Linq.Expressions.dll -> System.Linq.Expressions.dll.so
[90/128] System.Linq.dll -> System.Linq.dll.so
[91/128] System.Memory.dll -> System.Memory.dll.so
[92/128] System.Net.Http.dll -> System.Net.Http.dll.so
[93/128] System.Net.NameResolution.dll -> System.Net.NameResolution.dll.so
[94/128] System.Net.Primitives.dll -> System.Net.Primitives.dll.so
[95/128] System.Net.Requests.dll -> System.Net.Requests.dll.so
[96/128] System.Net.Sockets.dll -> System.Net.Sockets.dll.so
[97/128] System.Numerics.Vectors.dll -> System.Numerics.Vectors.dll.so
[98/128] System.ObjectModel.dll -> System.ObjectModel.dll.so
[99/128] System.Private.Uri.dll -> System.Private.Uri.dll.so
[100/128] System.Private.Xml.Linq.dll -> System.Private.Xml.Linq.dll.so
[101/128] System.Private.Xml.dll -> System.Private.Xml.dll.so
[102/128] System.Reflection.Extensions.dll -> System.Reflection.Extensions.dll.so
[103/128] System.Reflection.TypeExtensions.dll -> System.Reflection.TypeExtensions.dll.so
[104/128] System.Reflection.dll -> System.Reflection.dll.so
[105/128] System.Runtime.Extensions.dll -> System.Runtime.Extensions.dll.so
[106/128] System.Runtime.InteropServices.RuntimeInformation.dll -> System.Runtime.InteropServices.RuntimeInformation.dll.so
[107/128] System.Runtime.InteropServices.dll -> System.Runtime.InteropServices.dll.so
[108/128] System.Runtime.Loader.dll -> System.Runtime.Loader.dll.so
[109/128] System.Runtime.Numerics.dll -> System.Runtime.Numerics.dll.so
[110/128] System.Runtime.dll -> System.Runtime.dll.so
[111/128] System.Security.Cryptography.dll -> System.Security.Cryptography.dll.so
[112/128] System.Text.Encoding.dll -> System.Text.Encoding.dll.so
[113/128] System.Text.Encodings.Web.dll -> System.Text.Encodings.Web.dll.so
[114/128] System.Text.Json.dll -> System.Text.Json.dll.so
[115/128] System.Text.RegularExpressions.dll -> System.Text.RegularExpressions.dll.so
[116/128] System.Threading.Tasks.dll -> System.Threading.Tasks.dll.so
[117/128] System.Threading.Thread.dll -> System.Threading.Thread.dll.so
[118/128] System.Threading.ThreadPool.dll -> System.Threading.ThreadPool.dll.so
[119/128] System.Threading.dll -> System.Threading.dll.so
[120/128] System.Xml.Linq.dll -> System.Xml.Linq.dll.so
[121/128] System.Xml.ReaderWriter.dll -> System.Xml.ReaderWriter.dll.so
[122/128] System.Xml.XDocument.dll -> System.Xml.XDocument.dll.so
[123/128] System.dll -> System.dll.so
[124/128] netstandard.dll -> netstandard.dll.so
[125/128] Java.Interop.dll -> Java.Interop.dll.so
[126/128] Mono.Android.Runtime.dll -> Mono.Android.Runtime.dll.so
[127/128] Mono.Android.dll -> Mono.Android.dll.so
[128/128] System.Private.CoreLib.dll -> System.Private.CoreLib.dll.so
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:05:04.92
[11.0.0-prerelease.26230.4+92962e5c46ac08a66ded4c5696209cc60f1a232f] XHarness command issued: android test --app /home/vsts/work/1/s/artifacts/bin/Core.DeviceTests/Release/net10.0-android/com.microsoft.maui.core.devicetests-Signed.apk --package-name com.microsoft.maui.core.devicetests --device-id emulator-5554 -o artifacts/log --timeout 01:00:00 -v --arg TestFilter=Category=Switch
�[40m�[37mdbug�[39m�[22m�[49m: ADBRunner using ADB.exe supplied from /home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/tools/net10.0/any/../../../runtimes/any/native/adb/linux/adb
�[40m�[37mdbug�[39m�[22m�[49m: Full resolved path:'/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb'
�[40m�[32minfo�[39m�[22m�[49m: Will attempt to find device supporting architectures: 'arm64-v8a', 'x86_64'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb start-server'
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[32minfo�[39m�[22m�[49m: Finding attached devices/emulators...
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb devices -l'
�[40m�[37mdbug�[39m�[22m�[49m: Found 1 possible devices
�[40m�[37mdbug�[39m�[22m�[49m: Evaluating output line for device serial: emulator-5554 device product:sdk_gphone_x86_64 model:sdk_gphone_x86_64 device:generic_x86_64_arm64 transport_id:2
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell getprop ro.product.cpu.abilist'
�[40m�[37mdbug�[39m�[22m�[49m: Found 1 possible devices. Using 'emulator-5554'
�[40m�[32minfo�[39m�[22m�[49m: Active Android device set to serial 'emulator-5554'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 -s emulator-5554 shell getprop ro.product.cpu.abi'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 -s emulator-5554 shell getprop ro.build.version.sdk'
�[40m�[32minfo�[39m�[22m�[49m: Waiting for device to be available (max 5 minutes)
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 wait-for-device'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 -s emulator-5554 shell getprop sys.boot_completed'
�[40m�[37mdbug�[39m�[22m�[49m: sys.boot_completed = '1'
�[40m�[37mdbug�[39m�[22m�[49m: Waited 0 seconds for device boot completion
�[40m�[37mdbug�[39m�[22m�[49m: Working with emulator-5554 (API 30)
�[40m�[37mdbug�[39m�[22m�[49m: Check current adb install and/or package verification settings
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell settings get global verifier_verify_adb_installs'
�[40m�[37mdbug�[39m�[22m�[49m: verifier_verify_adb_installs = 0
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell settings get global package_verifier_enable'
�[40m�[37mdbug�[39m�[22m�[49m: package_verifier_enable =
�[40m�[1m�[33mwarn�[39m�[22m�[49m: Installing debug apks on a device might be rejected with INSTALL_FAILED_VERIFICATION_FAILURE. Make sure to set 'package_verifier_enable' to '0'
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.core.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.core.devicetests'
�[40m�[32minfo�[39m�[22m�[49m: APK 'com.microsoft.maui.core.devicetests' was not on device
�[40m�[32minfo�[39m�[22m�[49m: Attempting to install /home/vsts/work/1/s/artifacts/bin/Core.DeviceTests/Release/net10.0-android/com.microsoft.maui.core.devicetests-Signed.apk
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 install /home/vsts/work/1/s/artifacts/bin/Core.DeviceTests/Release/net10.0-android/com.microsoft.maui.core.devicetests-Signed.apk'
�[40m�[32minfo�[39m�[22m�[49m: Successfully installed /home/vsts/work/1/s/artifacts/bin/Core.DeviceTests/Release/net10.0-android/com.microsoft.maui.core.devicetests-Signed.apk
�[40m�[32minfo�[39m�[22m�[49m: Killing all running processes for 'com.microsoft.maui.core.devicetests':
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell am kill --user all com.microsoft.maui.core.devicetests'
�[40m�[37mdbug�[39m�[22m�[49m: Success!
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 logcat -b all -c'
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 logcat -P "'\"""\"""'"'
�[40m�[1m�[33mwarn�[39m�[22m�[49m: Unable to disable chatty. Logcat may hide what it finds to be repeating entries.
�[40m�[32minfo�[39m�[22m�[49m: Starting default instrumentation class on com.microsoft.maui.core.devicetests (exit code 0 == success)
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 shell am instrument -e TestFilter Category=Switch -w com.microsoft.maui.core.devicetests'
�[40m�[32minfo�[39m�[22m�[49m: Running instrumentation class {default} took 12.8768825 seconds
�[40m�[37mdbug�[39m�[22m�[49m: Exit code: 0
Std out:
INSTRUMENTATION_RESULT: return-code=1
INSTRUMENTATION_RESULT: test-execution-summary=Tests run: 70 Passed: 66 Inconclusive: 0 Failed: 1 Ignored: 3
INSTRUMENTATION_RESULT: test-results-path=/storage/emulated/0/Download/com.microsoft.maui.core.devicetests/61d3f4e081b24c3289da959ecbc258d1/testResults.xml
INSTRUMENTATION_CODE: -1
�[40m�[32minfo�[39m�[22m�[49m: Found XML result file: '/storage/emulated/0/Download/com.microsoft.maui.core.devicetests/61d3f4e081b24c3289da959ecbc258d1/testResults.xml'(key: test-results-path)
�[40m�[32minfo�[39m�[22m�[49m: Attempting to pull contents of /storage/emulated/0/Download/com.microsoft.maui.core.devicetests/61d3f4e081b24c3289da959ecbc258d1/testResults.xml to /home/vsts/work/1/s/artifacts/log
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 pull /storage/emulated/0/Download/com.microsoft.maui.core.devicetests/61d3f4e081b24c3289da959ecbc258d1/testResults.xml /tmp/dl1gbbca.w1r'
�[40m�[1m�[33mwarn�[39m�[22m�[49m: Skipping file copy as /home/vsts/work/1/s/artifacts/log/testResults.xml already exists
�[40m�[37mdbug�[39m�[22m�[49m: Copied 0 files to /home/vsts/work/1/s/artifacts/log
�[40m�[32minfo�[39m�[22m�[49m: Test execution summary:
Tests run: 70 Passed: 66 Inconclusive: 0 Failed: 1 Ignored: 3
�[40m�[32minfo�[39m�[22m�[49m: Instrumentation finished normally with exit code 1
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 logcat -d '
�[40m�[32minfo�[39m�[22m�[49m: Wrote full ADB log (375 lines) to /home/vsts/work/1/s/artifacts/log/adb-logcat-com.microsoft.maui.core.devicetests-default.log
�[40m�[32minfo�[39m�[22m�[49m: ADB log contained no DOTNET-tagged entries (see full log file for details)
�[41m�[30mfail�[39m�[22m�[49m: Non-success instrumentation exit code: 1, expected: 0
�[40m�[32minfo�[39m�[22m�[49m: <<XHARNESS_RESULT_START>>
{
"version": 1,
"machineName": "runnervmm79r7",
"exitCode": 1,
"exitCodeName": "TESTS_FAILED",
"platform": "android",
"instrumentationExitCode": 1,
"device": "emulator-5554",
"deviceOsVersion": "API 30",
"architecture": "x86_64",
"files": [
{
"name": "testResults.xml",
"type": "test-results"
},
{
"name": "adb-logcat-com.microsoft.maui.core.devicetests-default.log",
"type": "logcat"
}
]
}
<<XHARNESS_RESULT_END>>
�[40m�[32minfo�[39m�[22m�[49m: Attempting to remove apk 'com.microsoft.maui.core.devicetests'..
�[40m�[37mdbug�[39m�[22m�[49m: Executing command: '/home/vsts/.nuget/packages/microsoft.dotnet.xharness.cli/11.0.0-prerelease.26230.4/runtimes/any/native/adb/linux/adb -s emulator-5554 uninstall com.microsoft.maui.core.devicetests'
�[41m�[30mfail�[39m�[22m�[49m: Waiting for command timed out: execution may be compromised
�[41m�[30mfail�[39m�[22m�[49m: Error: Exit code: -2
Std out:
XHarness exit code: 1 (TESTS_FAILED)
Tests completed with exit code: 1
⚠️ Failure Details
- ❌ SwitchHandlerTests (DefaultSwitchReappliesLegacyOffTrackColorBeforeiOSOrMacCatalyst26, CustomColorsUseSlidingStyleOniOSOrMacCatalyst26, CustomColorsRenderOnInitialOffStateOniOSOrMacCatalyst26, DefaultSwitchUsesAutomaticStyleOniOSOrMacCatalyst26, ThumbColorClearsWhenResetOniOSOrMacCatalyst26, CustomColorsClearToAutomaticStyleOniOSOrMacCatalyst26, CustomColorsReapplyAfterMovedToWindowOniOSOrMacCatalyst26, QueuedColorReapplyDoesNotUpdateStaleNativeSwitchAfterReconnectOniOSOrMacCatalyst26, CustomColorsReapplyAfterWillEnterForegroundOniOS26, CustomColorsUpdateAfterAppThemeChangeOniOSOrMacCatalyst26) FAILED with fix (should pass)
📁 Fix files reverted (3 files)
eng/pipelines/ci-copilot.ymlsrc/Core/src/Handlers/Switch/SwitchHandler.iOS.cssrc/Core/src/Platform/iOS/SwitchExtensions.cs
New files (not reverted):
src/Core/src/Platform/iOS/MauiSwitch.cs
UI Tests — ViewBaseTests
Detected UI test categories: ViewBaseTests
✅ Deep UI tests — 118 passed, 0 failed across 1 category on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
ViewBaseTests |
118/119 ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
Pre-Flight — Context & Validation
Issue: #35257 - Switch custom colors are ignored on iOS 26
PR: #35385 - [iOS] Fix Switch custom colors on iOS 26
Platforms Affected: iOS, MacCatalyst. Requested try-fix test platform: android.
Files Changed: 3 implementation, 10 test/snapshot/host-app
Key Findings
- PR changes are iOS/MacCatalyst-specific:
SwitchHandler.iOS.cs, newMauiSwitch.cs, andSwitchExtensions.csimplement style switching and color reapply for iOS/MacCatalyst 26+. - Current PR fix opts customized switches into
UISwitchStyle.Sliding, preservesAutomaticfor unstyled switches, re-applies custom colors after UIKit lifecycle/style resets, and clears native thumb tint whenThumbColorresets tonull. - The supplied gate result failed on android, but the implementation files are iOS-only; Android testing cannot directly validate the iOS 26 regression fix.
- GitHub CLI auth was unavailable, so PR/issue/review metadata was gathered from public GitHub API and local diff instead of
gh.
Code Review Summary
Verdict: LGTM
Confidence: medium
Errors: 0 | Warnings: 2 | Suggestions: 3
Key code review findings:
⚠️ src/Core/src/Platform/iOS/MauiSwitch.cs:108—TryReapplyColorscalls low-level apply methods directly and relies onPreferredStylealready beingSliding.⚠️ src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs:161— UIKit-triggered reapply calls platform extension methods directly, bypassing mapper customizations.- 💡
src/Core/src/Platform/iOS/MauiSwitch.cs:62— trait-change reapply is redundant with the proxy's user-interface-style registration. - 💡
src/Core/src/Platform/iOS/SwitchExtensions.cs:140— non-MauiSwitchfallback in style reapply is unreachable throughSwitchHandler. - 💡
src/Core/tests/DeviceTests/Handlers/Switch/SwitchHandlerTests.iOS.cs:107— test helper uses deprecatedUIGraphics.BeginImageContextWithOptions.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #35385 | Use MauiSwitch plus iOS/MacCatalyst 26 style switching and deferred color reapply. |
❌ FAILED (Gate: Android, unrelated to iOS-only implementation) | SwitchHandler.iOS.cs, MauiSwitch.cs, SwitchExtensions.cs |
Original PR fix. |
Code Review — Deep Analysis
Code Review — PR #35385
Independent Assessment
What this changes: Creates a MauiSwitch : UISwitch subclass that self-manages a color-reapply lifecycle (overriding MovedToWindow, LayoutSubviews, TraitCollectionDidChange). Overhauling SwitchExtensions.UpdateTrackColor/UpdateThumbColor to switch UISwitch.PreferredStyle between Sliding (custom colors, iOS/Mac 26+) and Automatic (default). SwitchProxy.Disconnect now properly nulls weak references. MauiProgram.cs widens #if MACCATALYST to #if IOS || MACCATALYST for test runner argument reading.
Inferred motivation: iOS/macOS 26 shipped a "Liquid Glass" UISwitch style (UISwitchStyle.Automatic) that resets custom ThumbTintColor, OnTintColor, and track subview BackgroundColor at various UIKit lifecycle points — initial layout, MovedToWindow, theme changes, and foreground re-entry. The old code had only a partial fix (re-apply after WillEnterForeground with a Task.Delay(10) guard). This PR extends that pattern into a systematic, debounced reapply engine inside MauiSwitch.
Reconciliation with PR Narrative
Author claims: The PR title/commit is "PR #35385 squashed for review" (CI commit), so the actual PR description was not directly accessible. Based on code context, the fix targets the iOS/Mac 26 Switch color regression also addressed in the predecessor PR #33953 (bcd5905edb). This PR is a broader rework of that fix.
Agreement: The code does what the inferred intent describes. The architecture is sound and follows MAUI's MauiButton/MauiLabel subclass pattern.
Findings
⚠️ Warning — TryReapplyColors bypasses UpdatePreferredStyle
File: src/Core/src/Platform/iOS/MauiSwitch.cs, lines 107–110
TryReapplyColors calls this.ApplyTrackColor(virtualView) / this.ApplyThumbColor(virtualView) directly — these are the low-level color setters that skip UpdatePreferredStyle. On iOS/Mac 26+, colors only render correctly in UISwitchStyle.Sliding. The initial mapper call sets PreferredStyle = Sliding synchronously, and UIKit does not appear to reset it. However, if that assumption breaks (e.g., a future OS version, or a view hierarchy teardown-reconnect), this reapply path would apply colors in Automatic style where they are silently ignored.
In practice this is guarded by IsReadyForColorReapply() (view must be in window with non-zero bounds), and the mapper path runs before MovedToWindow fires — so PreferredStyle should be Sliding by the time TryReapplyColors can succeed. Worth a code comment to document the assumption.
⚠️ Warning — UIKit reapply bypasses mapper customizations
File: src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs, line 161
UpdateThumbAndTrackColor calls platformView.UpdateTrackColor(view) / platformView.UpdateThumbColor(view) directly rather than routing through handler.UpdateValue(nameof(ISwitch.TrackColor)). This bypasses AppendToMapping/PrependToMapping customizations. If an app developer registered a mapper extension on TrackColor or ThumbColor, that customization would be dropped on every UIKit-triggered reapply (theme change, foreground re-entry). This is a known MAUI anti-pattern (see handler-patterns guidelines). Should be documented with a comment explaining why the mapper bypass is intentional here.
💡 Suggestion — Redundant trait-change reapply path
File: src/Core/src/Platform/iOS/MauiSwitch.cs, line 62
MauiSwitch.TraitCollectionDidChange fires for ALL trait types, while SwitchProxy._traitChangeRegistration is scoped to UITraitUserInterfaceStyle. On iOS 26+ theme changes, both paths fire and both trigger async color reapplication. Idempotent but redundant. Consider removing TraitCollectionDidChange from MauiSwitch since the proxy registration already handles the main scenario, or document why the broader hook is needed.
💡 Suggestion — ReapplyColorsAfterStyleUpdate unreachable else branch
File: src/Core/src/Platform/iOS/SwitchExtensions.cs, lines 136–144
The else branch for non-MauiSwitch instances is unreachable through SwitchHandler, which always creates MauiSwitch. May be intentional for non-handler consumers of UpdateTrackColor/UpdateThumbColor. If not, simplify to the MauiSwitch-only path.
💡 Suggestion — Deprecated API in test helper
File: src/Core/tests/DeviceTests/Handlers/Switch/SwitchHandlerTests.iOS.cs, line ~107
CaptureRenderedSwitch uses UIGraphics.BeginImageContextWithOptions which is deprecated in iOS 16+. Recommended replacement: UIGraphicsImageRenderer. Minor in test code.
Devil's Advocate
Challenge: Is the gate failure caused by this PR?
The gate ran on "Platform: ANDROID" but all changed files are iOS-only (.iOS.cs, Platform/iOS/). No Android code was changed. The failing test ThumbColorUpdatesCorrectly exists in the shared Switch category on Android and has no relationship to the iOS changes. This is most likely a pre-existing Android test flake or a gate configuration issue. The gate result should be treated as a gate infrastructure failure, not a code regression.
Challenge: Is _isReapplyingColors guard necessary?
TryReapplyColors always runs on the main thread via DispatchAsync. Since UIKit is single-threaded, re-entrancy cannot occur. The guard is harmless defensive programming.
Challenge: Could _needsColorReapply create a perpetual reapply loop?
UpdateThumbAndTrackColor → pipeline → SetNeedsColorReapply() → TryReapplyColors → _needsColorReapply = false. Each cycle terminates. No loop.
Verdict: LGTM
Confidence: medium (iOS 26 platform behavior cannot be verified in this review environment)
Summary: The implementation is architecturally sound, follows the MauiSwitch subclass pattern used elsewhere in MAUI, and adds comprehensive device test coverage for all the new iOS 26 scenarios. The two warnings (style bypass in TryReapplyColors, mapper bypass in UpdateThumbAndTrackColor) are implementation choices that work correctly today under their stated assumptions, and are worth documenting with inline comments. The gate failure on Android is unrelated to this PR. Ready for human reviewer sign-off.
Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | maui-expert-reviewer | Remove MauiSwitch; route delayed reapply through handler.UpdateValue so mapper customizations and style updates are honored. |
❌ Failed / environment-blocked | 3 implementation files | Android device-test command built assemblies but VSTest aborted with libhostpolicy.so/runtimeconfig error before tests ran. |
| 2 | maui-expert-reviewer | Keep MauiSwitch, but make TryReapplyColors mapper-aware and replace Task.Delay(10) proxy work with nested main-queue dispatches that re-arm MauiSwitch. |
2 implementation files | Android execution blocked by same test-host issue; best-effort iOS build blocked by missing Microsoft.iOS.Sdk.net10.0_26.0 workload. |
|
| 3 | maui-expert-reviewer | Eager style-only approach: create plain UISwitch, force UISwitchStyle.Sliding on iOS/MacCatalyst 26+, delete MauiSwitch and most reapply machinery. |
3 implementation files | Simpler but likely regresses unstyled iOS 26 switches by forcing classic style instead of preserving native Automatic. |
|
| PR | PR #35385 | Use MauiSwitch plus conditional iOS/MacCatalyst 26 style switching and deferred color reapply; preserve Automatic for unstyled switches. |
❌ FAILED (Gate: Android) | 3 implementation files + tests/snapshots | Original PR fix. Android gate does not directly exercise iOS-only implementation. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| maui-expert-reviewer | 1 | Yes | Candidate 1: no-subclass mapper-routed reapply. |
| maui-expert-reviewer | 2 | Yes | Candidate 2: keep subclass but route final reapply through mapper and remove wall-clock delay. |
| maui-expert-reviewer | 3 | Yes | Candidate 3: eager style-only fix with no lifecycle state machine. |
| orchestrator | 4 | No | Meaningfully different families are exhausted: no-subclass mapper reapply, subclass mapper reapply, and style-only. Further variants would be timing tweaks rather than independent approaches. |
Exhausted: Yes
Selected Fix: PR #35385 — none of the alternatives passed all tests or was demonstrably better. Candidate 2 is the most promising improvement idea because it addresses mapper-bypass concerns while preserving the PR's lifecycle robustness, but it remains unvalidated in this environment. Candidate 3 is simpler but likely worse because it changes default unstyled iOS 26 switch appearance.
Failure/Blocker Summary
- Requested test platform was Android, but the PR and all candidates modify iOS/MacCatalyst-only files.
- The Android
dotnet testcommand used for try-fix-1 did not execute tests; VSTest aborted with alibhostpolicy.so/runtimeconfig host error. - Direct iOS build validation is unavailable on this Linux host because
Microsoft.iOS.Sdk.net10.0_26.0workload packs are missing. - Because no candidate passed tests, no alternative can be recommended over the PR fix.
Report — Final Recommendation
Comparative Report — PR #35385
Candidate ranking
| Rank | Candidate | Test/regression status | Assessment |
|---|---|---|---|
| 1 | pr-plus-reviewer |
Microsoft.iOS.Sdk.net10.0_26.0; Android gate not re-run by instruction |
Best candidate. Keeps the PR's iOS/MacCatalyst 26 lifecycle/style strategy and applies the expert reviewer's actionable mapper-aware reapply fix. |
| 2 | try-fix-2 |
Technically similar to pr-plus-reviewer and addresses the mapper-bypass issue, but as an independent try-fix it remained unvalidated and is superseded by applying the same improvement to the PR-reviewed candidate. |
|
| 3 | pr |
❌ Gate failed on Android; failure is not directly meaningful for iOS-only implementation | The raw PR preserves native defaults and has broad lifecycle coverage, but the expert reviewer found a major mapper-bypass issue in MauiSwitch.TryReapplyColors. |
| 4 | try-fix-1 |
❌ Failed/environment-blocked: Android VSTest aborted before tests ran with libhostpolicy.so/runtimeconfig error |
Routes proxy reapply through the mapper but removes MauiSwitch, losing the PR's layout/window reapply safety net for iOS 26 UIKit resets. |
| 5 | try-fix-3 |
Simplest style-only approach, but likely regresses product behavior by forcing unstyled iOS/MacCatalyst 26 switches to classic Sliding instead of preserving native Automatic, and lacks lifecycle reapply coverage. |
No candidate has a clean regression-test pass in this environment. The only explicit gate failure is Android-based and does not directly exercise the iOS/MacCatalyst-only fix, but candidates with failed regression execution are still ranked below the stronger blocked/code-reviewed candidates where appropriate.
Detailed comparison
pr
The raw PR introduces MauiSwitch, switches customized iOS/MacCatalyst 26 switches to UISwitchStyle.Sliding, keeps unstyled switches on Automatic, reapplies custom colors after UIKit lifecycle/style resets, and clears native tint state when custom colors are removed. This is the most complete product-oriented approach among the original candidates, but the expert reviewer identified a concrete mapper customization bug: lifecycle reapply calls low-level ApplyTrackColor/ApplyThumbColor directly and can overwrite app/library mapper extensions after trait/window/layout events.
pr-plus-reviewer
This candidate keeps the raw PR's architecture and applies the expert reviewer feedback by making the final lifecycle reapply mapper-aware. It avoids the raw PR's customization bypass while preserving the important safeguards that try-fix-1 and try-fix-3 weaken or remove. Its validation is blocked by the same missing iOS workload pack as other iOS-specific candidates, but by code review it is the best balance of correctness, compatibility, and risk.
try-fix-1
This candidate removes MauiSwitch and routes delayed callbacks through handler.UpdateValue. The mapper behavior is better than the raw PR, but removing the subclass also removes the broader layout/window/trait reapply state machine that appears central to the iOS 26 UIKit reset workaround. Its Android test command failed before executing tests, so there is no empirical evidence that the simplification is safe.
try-fix-2
This candidate is the strongest STEP 5a alternative: it keeps MauiSwitch, routes final reapply through the mapper, and removes wall-clock delay from proxy callbacks in favor of queued main-thread reapply. It is effectively the basis for pr-plus-reviewer. It remains blocked by test/build environment limitations, so it is ranked below the PR-applied reviewer candidate only because pr-plus-reviewer is the explicitly reviewed PR candidate requested by Phase 1.
try-fix-3
This candidate eagerly forces UISwitchStyle.Sliding for all iOS/MacCatalyst 26 switches and deletes the reapply machinery. That simplicity likely changes default unstyled switch appearance and leaves fewer protections against later UIKit resets. It should not win without iOS 26 visual/device evidence.
Winner
Winner: pr-plus-reviewer
pr-plus-reviewer wins because it preserves the PR's intended iOS 26 behavior and lifecycle resilience while fixing the expert reviewer's actionable mapper-customization issue. No candidate has passing regression evidence in this environment, and none of the try-fix alternatives is demonstrably safer or more complete.
Future Action — review latest findings
No alternative fix was selected for this run. Review the session findings and CI results before merging.
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
kubaflo
left a comment
There was a problem hiding this comment.
it looks like regression - I compared switches and they look incorrectly now
Description of Change
Fixes iOS 26
Switchcustom color rendering by using UIKit's public classic sliding switch style when MAUI switch colors are customized.On iOS 26, the automatic/liquid
UISwitchstyle can ignore MAUIOffColor/OnColortrack tinting andThumbColor. This change opts switches with a non-null MAUI track or thumb color intoUISwitchStyle.Slidingon iOS 26+, while leaving unstyled switches asUISwitchStyle.Automaticto preserve the native default appearance.This also:
ThumbTintColorwhenThumbColoris reset tonull.Issue35257Appium visual regression coverage from [iOS 26] Fix Switch ThumbColor and OffColor not applied on initial load #35400 and adds focused iOS handler tests for the style, reset, theme-change, and reattachment paths.Conflict resolution:
inflight/current.Issue35257HostApp page, Appium test, andIssue35257_*snapshots as the source of truth for visual coverage.SwitchCustomColorsRenderOnInitialStatesnapshot/test shape during conflict resolution.Validation performed:
dotnet build src/Core/src/Core.csproj -f net10.0-ios26.0 -c Debug --no-restoredotnet build src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj -c Debug --no-restoreIssues Fixed
Fixes #35257